package client_server;

import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;

import javax.swing.JOptionPane;

import parameters.RLM_Parameters;
import upnp.UPnpManager;
import utils.Constants;
import utils.MessageViewer;
import client.ClientApplication;


/**
 * RAF_LAN_Messenger Client Side Server
 * 
 * @author UrosKrkic & Radivoje Popovic
 */
public class ClientServer extends Thread implements Constants {
	
	/**
	 * Referenca na objekat aplikacije.
	 */
	private ClientApplication theApp;
	
	/**
	 * Listen Socket - osluskivac.
	 */
	private ServerSocket listenSocket;
	
	/**
	 * IP adresa klijenta.
	 */
//	private String ip_address;
	
	/**
	 * Port na kome se izvrsava serverski proces klijenta.
	 */
//	private int port;
	
	
	/**
	 * Konstruktor.
	 * @param theApp - referenca na objeka aplikacije.
	 * @author UrosKrkic & Radivoje Popovic
	 */
	public ClientServer(ClientApplication theApp) {
		this.theApp = theApp;
		
		try {	
//			listenSocket = new ServerSocket(0);
//			this.port = listenSocket.getLocalPort();
			
			String nicToConnect = RLM_Parameters.getNetworkInterfaceToConnect();
			
			
			// for LAN usage
			if ( !RLM_Parameters.isLan() ) {
				
				// zbog discavery timeout-a
				try {
					Thread.sleep(4000);
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				
				boolean tcpForwardFlag = UPnpManager.addTcpForward("RLM_Client_TCP", RLM_Parameters.getTcpPort(), RLM_Parameters.getTcpPort(), nicToConnect);
				boolean audioForwardFlag = UPnpManager.addUdpForward("RLM_Client_Audio", RLM_Parameters.getAudioPort(), RLM_Parameters.getAudioPort(), nicToConnect);
				boolean videoForwardFlag = UPnpManager.addUdpForward("RLM_Client_Video", RLM_Parameters.getVideoPort(), RLM_Parameters.getVideoPort(), nicToConnect);
				
	//			UPnpManager.addTcpAndUdpForward("RLM_Client", RLM_Parameters.getTcpPort(), RLM_Parameters.getTcpPort());
				
				if ( tcpForwardFlag == false || audioForwardFlag == false || videoForwardFlag == false ) {
					String msg = String.format("UPnp forward to ports %d or %d failed. Please forward the ports specified manually !", RLM_Parameters.getTcpPort(), RLM_Parameters.getAudioPort());
					JOptionPane.showMessageDialog(null, msg, "Warning!", JOptionPane.WARNING_MESSAGE);
					ClientApplication.clientServerSemaphore.release();
					return;
				}
			}
			
			listenSocket = new ServerSocket();
			InetSocketAddress isa = new InetSocketAddress(InetAddress.getByName(nicToConnect), RLM_Parameters.getTcpPort());
			listenSocket.bind(isa);
		} 
		catch (IOException ioe) {
			MessageViewer.showError(this.theApp.getWindow(), ioe.getMessage());
			return;
		}

//		theApp.setClientSideServerPort(this.port);
		
		this.start();
		
		ClientApplication.clientServerSemaphore.release();
	}

	
	@Override
	public void run() {
		try {
			System.out.println("RLM Client Side Server running at port: " + RLM_Parameters.getTcpPort());
			
			while (true) {
				
				Socket connectionSocket = listenSocket.accept();
				
				/* 
				 * Pokretanje thread-a koji procesira zahteve.
				 */
				new ClientServerProcessing(theApp, connectionSocket);
			}
		}
		catch (IOException ioe) {
//			ioe.printStackTrace();
			ClientApplication.bindingSemaphore.release();
			System.out.println("Socket closed");
			return;
		}
	}
	
	
	/**
	 * Metos setuje IP adresu serverskog procesa klijenta.
	 * @param address - IP adresa
	 * @author UrosKrkic & Radivoje Popovic
	 */
//	public void setIPAddress(InetAddress address) {
//		this.ip_address = address.getHostAddress();
//	}
	
	
	/**
	 * Metod vraca IP adresu serverskog procesa klijenta.
	 * @return - IP adresa
	 * @author UrosKrkic & Radivoje Popovic
	 */
//	public String getIP_address() {
//		return ip_address;
//	}
	

	/**
	 * Metod vraca port serverskog procesa klijenta.
	 * @return broj porta
	 * @author UrosKrkic & Radivoje Popovic
	 */
//	public int getPort() {
//		return port;
//	}
	
	
	/**
	 * Metod zaustavlja serverski proces na klijentskoj strani.
	 * @author UrosKrkic & Radivoje Popovic
	 */
	public void stopClientServer() {
		try {
			listenSocket.close();
			this.interrupt();
		}
		catch (IOException ioe) {
			ioe.printStackTrace();
			return;
		}
	}
	
	
	
	@Override
	public void interrupt() {
		super.interrupt();
	}
	
}
